package org.firefly.service;

import org.firefly.entity.TimeCapsule;
import org.firefly.entity.TimeCapsule.CapsuleType;
import org.firefly.entity.User;
import org.firefly.exception.CapsuleNotFoundException;
import org.firefly.job.CapsuleOpenJob;
import org.firefly.repository.TimeCapsuleRepository;
import lombok.RequiredArgsConstructor;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Value;

@Service
@RequiredArgsConstructor
public class TimeCapsuleService {
    private static final Logger log = LoggerFactory.getLogger(TimeCapsuleService.class);

    private final TimeCapsuleRepository capsuleRepository;
    private final Scheduler scheduler;
    private final EmailService emailService;

    @Value("${app.media.storage-path}")
    private String mediaStoragePath;

    @Transactional
    public TimeCapsule createCapsule(User user, String title, String content,
                                     LocalDateTime openDate, String recipientEmail,
                                     MultipartFile mediaFile) throws IOException {

        TimeCapsule capsule = new TimeCapsule();
        capsule.setUser(user);
        capsule.setTitle(title);
        capsule.setContent(content);
        capsule.setOpenDate(openDate);
        capsule.setRecipientEmail(recipientEmail);

        if (mediaFile != null && !mediaFile.isEmpty()) {
            String mediaPath = saveMediaFile(mediaFile);
            capsule.setMediaPath(mediaPath);
            capsule.setType(determineCapsuleType(mediaFile.getContentType()));
        }

        TimeCapsule savedCapsule = capsuleRepository.save(capsule);

        // 只对时间胶囊调度任务（位置胶囊由LocationTriggerService处理）
        if (savedCapsule.getType() != CapsuleType.LOCATION) {
            scheduleCapsuleOpening(savedCapsule);
        }

        return savedCapsule;
    }

    private CapsuleType determineCapsuleType(String contentType) {
        if (contentType == null) return CapsuleType.TEXT;
        if (contentType.startsWith("image")) return CapsuleType.IMAGE;
        if (contentType.startsWith("audio")) return CapsuleType.AUDIO;
        if (contentType.startsWith("video")) return CapsuleType.VIDEO;
        return CapsuleType.TEXT;
    }

    private String saveMediaFile(MultipartFile file) throws IOException {
        String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
        Path storagePath = Paths.get(mediaStoragePath);

        if (!Files.exists(storagePath)) {
            Files.createDirectories(storagePath);
        }

        Path filePath = storagePath.resolve(fileName);
        Files.copy(file.getInputStream(), filePath);

        return fileName;
    }

    // 修改为公共方法，供任务恢复机制调用
    public void scheduleCapsuleOpening(TimeCapsule capsule) {
        try {
            // 确保开启时间在未来
            if (capsule.getOpenDate().isBefore(LocalDateTime.now())) {
                log.warn("Cannot schedule past capsule: {}", capsule.getId());
                return;
            }

            JobDetail job = JobBuilder.newJob(CapsuleOpenJob.class)
                    .withIdentity("capsule_" + capsule.getId())
                    .usingJobData("capsuleId", capsule.getId())
                    .build();

            Trigger trigger = TriggerBuilder.newTrigger()
                    .startAt(java.sql.Timestamp.valueOf(capsule.getOpenDate()))
                    .build();

            scheduler.scheduleJob(job, trigger);
            log.info("Scheduled job for capsule ID: {}", capsule.getId());
        } catch (SchedulerException e) {
            log.error("Failed to schedule capsule job for ID: " + capsule.getId(), e);
            throw new RuntimeException("Failed to schedule capsule job", e);
        }
    }

    @Transactional
    public void openCapsule(Long capsuleId) {
        TimeCapsule capsule = capsuleRepository.findById(capsuleId)
                .orElseThrow(() -> new CapsuleNotFoundException(capsuleId));

        if (!capsule.isOpened()) {
            capsule.setOpened(true);
            capsuleRepository.save(capsule);
            emailService.sendCapsuleNotification(capsule);
            log.info("Capsule opened successfully: ID={}", capsuleId);
        }
    }

    public List<TimeCapsule> getUserCapsules(User user) {
        return capsuleRepository.findByUser(user);
    }

    public List<TimeCapsule> getPendingCapsules(User user) {
        return capsuleRepository.findByUserAndOpenedFalseAndOpenDateAfter(
                user, LocalDateTime.now());
    }

    // 新增方法：获取所有未开启的胶囊
    public List<TimeCapsule> getAllPendingCapsules() {
        return capsuleRepository.findByOpenedFalse();
    }

    @Scheduled(fixedRate = 300000) // 每5分钟运行一次
    public void checkPendingCapsules() {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime end = now.plusMinutes(10);

        List<TimeCapsule> capsules = capsuleRepository.findByOpenDateBetweenAndOpenedFalse(now, end);

        capsules.forEach(capsule -> {
            try {
                JobKey jobKey = new JobKey("capsule_" + capsule.getId());
                if (!scheduler.checkExists(jobKey)) {
                    scheduleCapsuleOpening(capsule);
                    log.info("Rescheduled capsule job: ID={}", capsule.getId());
                }
            } catch (SchedulerException e) {
                log.error("Error checking job existence for capsule: " + capsule.getId(), e);
            }
        });
    }

    @Transactional
    public void deleteCapsule(Long capsuleId) {
        TimeCapsule capsule = capsuleRepository.findById(capsuleId)
                .orElseThrow(() -> new CapsuleNotFoundException(capsuleId));

        // 删除媒体文件
        if (capsule.getMediaPath() != null) {
            deleteMediaFile(capsule.getMediaPath());
        }

        // 删除定时任务
        try {
            JobKey jobKey = new JobKey("capsule_" + capsuleId);
            if (scheduler.checkExists(jobKey)) {
                scheduler.deleteJob(jobKey);
                log.info("Deleted quartz job for capsule: ID={}", capsuleId);
            }
        } catch (SchedulerException e) {
            log.warn("Error deleting quartz job for capsule: " + capsuleId, e);
        }

        capsuleRepository.delete(capsule);
        log.info("Deleted capsule: ID={}", capsuleId);
    }

    private void deleteMediaFile(String fileName) {
        try {
            Path filePath = Paths.get(mediaStoragePath, fileName);
            Files.deleteIfExists(filePath);
            log.info("Deleted media file: {}", fileName);
        } catch (IOException e) {
            log.error("Failed to delete media file: " + fileName, e);
        }
    }

    // 新增方法：重新安排任务
    public void rescheduleCapsule(Long capsuleId) {
        TimeCapsule capsule = capsuleRepository.findById(capsuleId)
                .orElseThrow(() -> new CapsuleNotFoundException(capsuleId));

        try {
            // 删除现有任务
            JobKey jobKey = new JobKey("capsule_" + capsuleId);
            if (scheduler.checkExists(jobKey)) {
                scheduler.deleteJob(jobKey);
            }

            // 创建新任务
            scheduleCapsuleOpening(capsule);
            log.info("Rescheduled capsule job: ID={}", capsuleId);
        } catch (SchedulerException e) {
            log.error("Failed to reschedule capsule: " + capsuleId, e);
            throw new RuntimeException("Failed to reschedule capsule job", e);
        }
    }
}